package com.googlecode.c4e.api;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.maven.continuum.xmlrpc.ContinuumService;
import org.apache.maven.continuum.xmlrpc.client.ContinuumXmlRpcClient;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Plugin;
import org.osgi.framework.BundleContext;

import com.googlecode.c4e.api.model.BuildResult;
import com.googlecode.c4e.api.model.Project;
import com.googlecode.c4e.api.model.ProjectGroup;
import com.googlecode.c4e.api.model.Server;

/**
 * Provides methods for server and project management.
 * 
 * @author Tomasz Pik
 */
public class Registry extends Plugin {

	public static final String PLUGIN_ID = "com.googlecode.c4e.api";

	private static Registry plugin;

	public Registry() {
		plugin = this;
	}

	public void start(BundleContext context) throws Exception {
		super.start(context);
	}

	public void stop(BundleContext context) throws Exception {
		plugin = null;
		super.stop(context);
	}

	public static Registry getDefault() {
		return plugin;
	}

	public void discardServer(Server server) {
		if (server.getId() == null) {
			return;
		}
		String serverIdsString = getPluginPreferences().getString("servers");
		if ((serverIdsString == null) || (serverIdsString.trim().length() == 0)) {
			return;
		}
		String newServerIdsString = "";
		String[] serverIds = serverIdsString.split(",");
		for (String serverId : serverIds) {
			if (!serverId.trim().equals(server.getId().trim())) {
				if (newServerIdsString.length() > 0) {
					newServerIdsString = newServerIdsString + ",";
				}
				newServerIdsString = newServerIdsString + serverId;
			}
		}
		getPluginPreferences().setValue("servers", newServerIdsString);

		// TODO find a way for removing properties!
		getPluginPreferences()
				.setValue("server." + server.getId() + ".url", "");
		getPluginPreferences().setValue("server." + server.getId() + ".label",
				"");
		getPluginPreferences().setValue(
				"server." + server.getId() + ".username", "");
		try {
			Platform.flushAuthorizationInfo(new URL(server.getUrl()), server
					.getUsername(), "continuum");
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage(), e);
		}

		savePluginPreferences();
	}

	public void saveServer(Server server) {
		if (server.getId() == null) {
			server.setId(String.valueOf(System.currentTimeMillis()));
		}
		String serverIdsString = getPluginPreferences().getString("servers");
		if ((serverIdsString == null) || (serverIdsString.trim().length() == 0)) {
			serverIdsString = server.getId();
		} else {
			String[] serverIds = serverIdsString.split(",");
			boolean found = false;
			for (String serverId : serverIds) {
				if (serverId.trim().equals(server.getId().trim())) {
					found = true;
				}
			}
			if (!found) {
				serverIdsString = serverIdsString + "," + server.getId();
			}
		}
		getPluginPreferences().setValue("servers", serverIdsString);
		getPluginPreferences().setValue("server." + server.getId() + ".url",
				server.getUrl());
		getPluginPreferences().setValue("server." + server.getId() + ".label",
				server.getLabel());
		getPluginPreferences().setValue(
				"server." + server.getId() + ".username", server.getUsername());

		Map authInfo = new HashMap();
		if (server.getPassword() != null) {
			authInfo.put("password", server.getPassword());
		}
		try {
			Platform.addAuthorizationInfo(new URL(server.getUrl()), server
					.getUsername(), "continuum", authInfo);
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage(), e);
		}
		savePluginPreferences();
	}

	public List<Server> listServers() {
		List<Server> result = new ArrayList<Server>();
		String servers = getPluginPreferences().getString("servers");
		String[] serverIds = servers.split(",");
		for (String serverId : serverIds) {
			if (serverId.trim().length() > 0) {
				Server server = new Server();
				server.setId(serverId);
				server.setUrl(getPluginPreferences().getString(
						"server." + serverId + ".url"));
				server.setLabel(getPluginPreferences().getString(
						"server." + serverId + ".label"));
				server.setUsername(getPluginPreferences().getString(
						"server." + serverId + ".username"));
				try {
					Map authInfo = Platform.getAuthorizationInfo(new URL(server
							.getUrl()), server.getUsername(), "continuum");
					if (authInfo != null) {
						server.setPassword((String) authInfo.get("password"));
					}
				} catch (MalformedURLException mue) {
					throw new RuntimeException(mue.getMessage(), mue);
				}
				result.add(server);
			}
		}

		return result;
	}

	public BuildResult lastBuildResult(Project project) throws Exception {
		ContinuumService client = connect(project.getGroup().getServer());
		Map resultMap = client.getLatestBuildResultRPC(project.getId());
		Map projectMap = (Map) resultMap.get("project");
		int buildNumber = Integer.parseInt(String.valueOf(projectMap
				.get("latestBuildId")));
		BuildResult result = new BuildResult();
		result.setProject(project);
		result.setBuildNumber(buildNumber);
		result.setOutput(client.getBuildOutput(project.getId(), buildNumber));
		return result;
	}

	public List<ProjectGroup> listProjectGroups(Server server) throws Exception {
		ContinuumService client = connect(server);
		List<Object> summaries = client.getAllProjectGroupsRPC();
		List<ProjectGroup> result = new ArrayList<ProjectGroup>(summaries
				.size());
		for (Object summary : summaries) {
			Map summaryMap = (Map) summary;
			ProjectGroup group = new ProjectGroup();
			group.setId(Integer.valueOf(String.valueOf(summaryMap.get("id"))));
			group.setName(String.valueOf(summaryMap.get("name")));
			group.setGroupId(String.valueOf(summaryMap.get("groupId")));
			group.setDescription(String.valueOf(summaryMap.get("description")));
			group.setServer(server);
			result.add(group);
		}
		return result;
	}

	public Integer checkProjectState(Project project) throws Exception {
		ContinuumService client = connect(project.getGroup().getServer());
		Map summaryMap = client.getProjectSummaryRPC(project.getId());
		return Integer.valueOf(String.valueOf(summaryMap.get("state")));
	}

	public List<Project> listProjects(ProjectGroup projectGroup)
			throws Exception {
		ContinuumService client = connect(projectGroup.getServer());
		List<Object> summaries = client.getProjectsRPC(projectGroup.getId());
		List<Project> result = new ArrayList<Project>(summaries.size());
		for (Object summary : summaries) {
			Map summaryMap = (Map) summary;
			Project project = new Project();
			project.setGroup(projectGroup);
			project.setName(String.valueOf(summaryMap.get("name")));
			project.setArtifactId(String.valueOf(summaryMap.get("artifactId")));
			project.setGroupId(String.valueOf(summaryMap.get("groupId")));
			project.setVersion(String.valueOf(summaryMap.get("version")));
			project
					.setId(Integer
							.valueOf(String.valueOf(summaryMap.get("id"))));
			project.setState(Integer.valueOf(String.valueOf(summaryMap
					.get("state"))));
			project.setScmUrl(String.valueOf(summaryMap.get("scmUrl")));
			result.add(project);
		}
		return result;
	}

	public void buildProject(Project project) throws Exception {
		ContinuumService client = connect(project.getGroup().getServer());
		client.buildProject(project.getId());
	}

	private ContinuumService connect(Server server) throws Exception {
		String username = server.getUsername();
		if (isEmpty(username)) {
			username = null;
		}
		String password = server.getPassword();
		if (isEmpty(password)) {
			password = null;
		}
		ContinuumXmlRpcClient client = new ContinuumXmlRpcClient(new URL(server
				.getUrl()), username, password);
		return client;
	}

	private boolean isEmpty(String str) {
		return str == null || str.trim().length() == 0;
	}
}
